package com.vdimitr.happycube.puzzle.solution.output.conversion;

import java.util.LinkedList;
import java.util.List;

import com.vdimitr.happycube.puzzle.piece.PuzzlePiece;
import com.vdimitr.happycube.puzzle.solution.output.translation.IPuzzlePieceMatrixValueTranslator;

/**
 * This class is responsible for converting the matrix representation of a
 * puzzle piece solution to a matrix of strings, where each string represents
 * the concatenation of all the matrix representations of the puzzle pieces in a
 * row. The output of this class is ready for export.
 * 
 * @see PuzzlePiecesToStringConcantenator
 * @see PuzzlePieceMatrixRowToStringConverter
 * 
 * @author vasileios.dimitriadis
 * 
 */
public class PuzzlePieceSolutionMatrixToStringConverter {

	/**
	 * Used for concatenating rows of puzzle pieces
	 */
	private PuzzlePiecesToStringConcantenator concatinator = null;

	/**
	 * 
	 * @param translator
	 *            the value translator for converting the int values of matrix
	 *            representations of puzzle pieces to string
	 */
	public PuzzlePieceSolutionMatrixToStringConverter(
			IPuzzlePieceMatrixValueTranslator translator) {
		PuzzlePieceMatrixRowToStringConverter matrixRowToStringConverter = new PuzzlePieceMatrixRowToStringConverter(
				translator);
		this.concatinator = new PuzzlePiecesToStringConcantenator(
				matrixRowToStringConverter);
	}

	/**
	 * Converts the matrix representation of a puzzle piece solution to a matrix
	 * of strings
	 * 
	 * @param puzzlePieceSolutionMatrix
	 *            the matrix representation of a puzzle piece solution
	 * @return a matrix containing the string representation of a puzzle piece
	 *         solution
	 */
	public String[] toString(PuzzlePiece[][] puzzlePieceSolutionMatrix) {
		// List holding the string representations
		List<String> puzzlePieceSolutionStrings = new LinkedList<String>();
		// counter for the rows
		int puzzlePieceSolutionMatrixRowCounter = 0;
		// for each puzzle piece row
		while (puzzlePieceSolutionMatrixHasMoreRows(puzzlePieceSolutionMatrix,
				puzzlePieceSolutionMatrixRowCounter)) {
			// translate a row of puzzle pieces to a matrix of strings
			String[] puzzlePieceSolutionMatrixToString = concatinatePuzzlePieceMatrixSolutionRowsToString(
					puzzlePieceSolutionMatrix,
					puzzlePieceSolutionMatrixRowCounter);

			// add the strings to the final return list
			addPuzzlePieceSolutionMatrixToString(puzzlePieceSolutionStrings,
					puzzlePieceSolutionMatrixToString);

			// increase
			puzzlePieceSolutionMatrixRowCounter++;
		}
		// convert to array
		return puzzlePieceSolutionStrings
				.toArray(new String[puzzlePieceSolutionStrings.size()]);
	}

	/**
	 * Add the generated string representations to the final output
	 * 
	 * @param puzzlePieceSolutionStrings
	 *            the returned value
	 * @param puzzlePieceSolutionMatrixToString
	 *            a matrix of strings representing a row of puzzle pieces
	 */
	private void addPuzzlePieceSolutionMatrixToString(
			List<String> puzzlePieceSolutionStrings,
			String[] puzzlePieceSolutionMatrixToString) {
		for (String puzzlePieceSolutionMatrixString : puzzlePieceSolutionMatrixToString) {
			puzzlePieceSolutionStrings.add(puzzlePieceSolutionMatrixString);
		}
	}

	/**
	 * Check if the there are no more rows in the matrix
	 * 
	 * @param puzzlePieceSolutionMatrix
	 *            a NxM matrix containing puzzle pieces
	 * @param puzzlePieceRowCounter
	 *            the current row count
	 * @return true if there are still more rows in the matrix
	 */
	private boolean puzzlePieceSolutionMatrixHasMoreRows(
			PuzzlePiece[][] puzzlePieceSolutionMatrix, int puzzlePieceRowCounter) {
		return puzzlePieceRowCounter < puzzlePieceSolutionMatrix.length;
	}

	/**
	 * Convert a row of puzzle pieces to matrix of strings
	 * 
	 * @param puzzlePieceSolutionMatrix
	 *            the matrix representation of a puzzle piece solution
	 * @param puzzlePieceSolutionMatrixRowCounter
	 *            the row to convert
	 * @return a matrix containing the string concatenation of the matrix
	 *         Representations of the puzzle pieces in the specified row
	 */
	private String[] concatinatePuzzlePieceMatrixSolutionRowsToString(
			PuzzlePiece[][] puzzlePieceSolutionMatrix,
			int puzzlePieceSolutionMatrixRowCounter) {
		PuzzlePiece[] puzzlePieces = getRowOfPuzzlePieces(
				puzzlePieceSolutionMatrix, puzzlePieceSolutionMatrixRowCounter);
		return concatinator.concantenatePuzzlePiecesToString(puzzlePieces);
	}

	/**
	 * Get a row of the matrix
	 * 
	 * @param matrix
	 *            a NxM matrix with puzzle pieces
	 * @param rowIndex
	 *            the row to seek
	 * @return a matrix of puzzle pieces in the specified row
	 */
	private PuzzlePiece[] getRowOfPuzzlePieces(PuzzlePiece[][] matrix,
			int rowIndex) {
		return matrix[rowIndex];
	}

}
